<?php
namespace Managers;
use Lib\ResLoader,
    Lib\Model\DoctrineManager,
    Doctrine\ORM\Query\Expr\Func;

/**
 * Base class for models
 *
 * @since 23 июня 2010
 * @author diotheos
 */
class BaseManager extends DoctrineManager{

	protected $_defaultEntityName;

    protected static $_entityNamspace = 'Automoto';

	protected $__table;

	private $__cache;

	/**
	 * Тег для всех маленьких таблиц
	 * @todo Зробити очистку кеша по даному тегу десь в адмінці
	 * @var unknown_type
	 */
	public $_cache_tags = array('small_tables');

	public $_cache_time = 86400; // 60 * 60 * 24

    private $_cache_flag=1;

    /**
     *
     * Устанавливает ключем строки значение ключевого поля в строке
     * Необходимо при роботе с кешом, чтобы напрямую обращатся по ИДшке к елементу
     * @param array $array
     * @param string $key
     * @return array $asoc_array
     */
    public function toKey_Row($array, $key){
    	if(!sizeof($array))return $array;
    	$asoc_array = array();
    	foreach ($array as $item){
    		$asoc_array[$item[$key]]=$item;
    	}
    	return $asoc_array;
	}


    /**
     * @author megadevel
     */
     public function getCount(){
       $query = $this->_em->createQuery("SELECT COUNT(u.id) FROM ".$this->__table." u");
        return $query->getSingleScalarResult();
    }

	/**
    * @author megadevel
    * @since 24 нояб. 2010
    */
    public function getById($id) {
         $result = $this->_em->createQueryBuilder()
                    ->select('m')
                    ->from($this->__table, 'm')
                    ->where('m.id = :id')->setParameter('id', $id)
                    ->getQuery()
                    ->getArrayResult();

          return count($result) ? $result[0] :false;
    }

    /**
     * Get info by name
     * @param string $name
     */
    public function getPrivilegesByName($name) {
    	$result = $this->_em->createQueryBuilder()
    	->select('m')
    	->from($this->__table, 'm')
    	->where('m.name = :name')->setParameter('name', $name)
    	->getQuery()
    	->getArrayResult();

    	return isset($result[0])?$result[0]:false;
    }


	/**
	* @author megadevel
	* @since Jan 18, 2011
	* @param
	* @return
	*/
	public function updateFromArray($id, array $params) {
		$entity = $this->_em->find($this->__table, $id);
		if(!$entity)return false;
		$entity = $this->setFromArray($params, $entity);
		if(!$entity)return false;

		$this->_em->persist($entity);
        $this->_em->flush();
        return $entity;
	}


	/**
	* @author megadevel
	* @since Jan 18, 2011
	* @param
	* @return
	*/
	public function insertFromArray(array $params) {
		$entity = $this->setFromArray($params);
		if(!$entity)return false;

		$this->_em->persist($entity);
        $this->_em->flush();
        return $entity->getId();
	}

    /**
     * @author megadevel
     * @since Jan 18, 2011
     * @param $id
     * @return bool
     */
	public function delete($id) {
		$entity = $this->_em->find($this->__table, $id);
		if($entity){
			$this->_em->remove($entity);
			$this->_em->flush();
            return true;
		}
        return false;
	}


    /**
	* @author megadevel
	* @since Jan 17, 2011
	* @param
	* @return
	*/
	public function setFromArray(array $params, $entity=null) {
		$reflection = new \ReflectionClass($this->__table);
		$changes_flag = false;

		if(!$entity or !is_object($entity))
			$entity = new $this->__table;
		$property = array_keys($reflection->getDefaultProperties());

		foreach ($property as $item){
			//check is primary in DocComment
			if(strpos($reflection->getProperty($item)->getDocComment(), '@Id')>0)continue;
			if(strpos($comment = $reflection->getProperty($item)->getDocComment(), 'targetEntity=')>0){
                preg_match_all('#targetEntity="(.*?)"#', $comment, $searched);
                if(isset($searched[1][0]) && strlen($searched[1][0])){
                    $itemRefer = $this->_em->getReference(self::$_entityNamspace.'\\'.$searched[1][0], $params[$item]);
                }
            }

			if(isset($params[$item]) && $reflection->hasMethod($method = 'set'.ucfirst($item))){
				$entity->$method(isset($itemRefer)?$itemRefer:$params[$item]);
				$changes_flag=true;
			}
            unset($itemRefer);
		}
		if($changes_flag)return $entity;
		else return false;
	}


    /**
     * Генерируем имя ключа для кеша в зависимости от сущности
     * @param string $table
     */
    public function getCacheName($table = '', $prefix=''){
    	return 'My_table'.$prefix.str_replace("\\", '___', $table);
    }

    /**
     * Робота з кешом для простих таблиць (don't use MySQL)
     * Бере з регистра, якщо нема - ломиться в редіс і тільки потом в базу
     * @param string $table
     * @param integer $id
     * @fixme Зробити рефактор кода. Можливі потенційні проблеми
     * @return array
     */
    public function getFromCacheArray($table, $id=null){
    	$in_register = false;
        if (\Zend_Registry::isRegistered($cname = $this->getCacheName($table))) {
            $result = \Zend_Registry::get($cname);
            $in_register = true;
        }
        else{
            $result = $this->_getCacheManager()->load($cname);
        }

        //проверка есть ли таблица в кеше
        if(!$result){
	        $result = $this->getItems($table, null, true);
	        if(!count($result))return false;

	        $result = $this->toKey_Row($result, 'id');
	        $this->_getCacheManager()->save($result, $cname, $this->_cache_tags, $this->_cache_time);
        }

        if(!$in_register)\Zend_Registry::set($cname, $result);

        if(!$id)
            return $result;
        else {
        	if(is_array($id)){
        		$tmp_result = array();
        		foreach ($id as $item)$tmp_result[] = $result[$item];
        		return $tmp_result;
        		}
        	else {
        	    if(isset($result[$id]))
            	    return $result[$id];
            	return null;
        	}
        }
        }

    /**
     * @todo Рефактор + в конфиги вынести настройки
     * @return \Zend_Cache_Core
     */
    public function _getCacheManager(){
    	return \Lib\ResLoader::getResource('redis');
    }

    /**
     *
     * Простая робота с SQL строкой
     * @param string $qs
     * @param integer $memcache_time
     * @param string $memcahe_name
     */
    public function getArray($qs,$memcache_time=0,$memcahe_name='')
    {
    	if ($memcache_time) {
    		$data = $this->_getCacheManager()->load(self::getMemcacheName($qs, $memcahe_name));
    		if ($data !== false) return $data;
    	}
    	//if no data
    	$data = $this->getEntityManager()->getConnection()->executeQuery($qs)->fetchAll();
    	if ($memcache_time) {
    		$this->_getCacheManager()->save($data, self::getMemcacheName($qs, $memcahe_name), array('sql'));
    	}
    	return $data;
    }

    /**
     * Make memcache name
     * @param string $qs
     * @param string $name
     */
    protected static function getMemcacheName($qs,$name='') {
    	if ($name!='') $key = $name;
    	else $key = 'My_'.crc32($qs);

    	return $key;
    }

    /**
     * Возвращает массив-представление сущности.
     * @param object $entity
     * @return array|bool
     */
    public function entityToArray($entity) {
        if(!is_object($entity)) {
            return false;
        }
        $class = get_class($entity);
        $reflection = new \ReflectionClass($class);
        $vars = $reflection->getProperties();
        $result = array();
        foreach($vars as $var) {

            $name = $var->name;
            $method = 'get' . ucfirst($name);
            $value = call_user_func(array($entity,$method));
            if(is_object($value))  {
                $result[$name] = $this->entityToArray($value);
            } else {
                $result[$name] = $value;
            }
        }

        return $result;

    }

    /**
     * Not for USE
     * @param $query
     * @return array
     */
    public function getSimpleQuery($query){
        return $this->getEntityManager()->getConnection()->executeQuery($query)->fetchAll();
    }
}